home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2004 #6 / Amiga Plus CD - 2004 - No. 06.iso / AmiSoft / Comm / misc / trsi-ftpd01.lha / FAME-FTPd / source / main.c < prev    next >
C/C++ Source or Header  |  2004-04-24  |  53KB  |  1,733 lines

  1. /****************************************************************************************
  2.  *  PROJECT: FAME-FTPd
  3.  *     FILE: main.c
  4.  *  PURPOSE: Main file of FAME FTPd - A FTP server for FAME BBS systems
  5.  *  CREATED: 05-MAY-2003
  6.  * MODIFIED: 24-APR-2004
  7.  *   AUTHOR: Sascha 'SieGeL' Pfalz
  8.  *    NOTES: FTP parts taken from JornFTPd written by
  9.  *           Joran Jessurun <nl0jor@nl0jor.nl.cbpr.org> THX!
  10.  *           Also some codeparts are taken and adapted from wu-ftpd
  11.  ****************************************************************************************/
  12.  
  13. #include <proto/exec.h>
  14. #include <proto/dos.h>
  15. #include <proto/locale.h>
  16. #include <proto/utility.h>
  17. #include <proto/intuition.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <dos/stdio.h>
  21. #include <sys/types.h>
  22. #include <sys/syslog.h>
  23. #include <sys/socket.h>
  24. #include <sys/errno.h>
  25. #include <sys/param.h>
  26. #include <sys/stat.h>
  27. #include <sys/ioctl.h>
  28. #include <sys/file.h>
  29. #include <sys/wait.h>
  30. #include <sys/errno.h>
  31. #include <error.h>
  32. #include <exec/exec.h>
  33. #include <exec/nodes.h>
  34. #include <exec/lists.h>
  35. #include <utility/date.h>
  36. #include <utility/tagitem.h>
  37. #include <proto/socket.h>
  38. #include <netinet/in.h>
  39. #include <amitcp/socketbasetags.h>
  40. #include <netdb.h>
  41. #include <arpa/nameser.h>
  42. #include <netinet/in.h>
  43. #include <proto/fame.h>
  44. #include <libraries/fame.h>
  45. #include <fame/fame.h>
  46. #include <proto/syslog.h>
  47. #include <libraries/syslog.h>
  48. #include <lineread.h>
  49. #include <devices/timer.h>
  50.  
  51. #include "version.h"
  52. #include "proto.h"
  53. #include "ftp.h"
  54. #include "struct.h"
  55.  
  56. const     char *ver="$VER: FAME-FTPd "COMPILE_VERSION" ("COMPILE_DATE") ["CPU_TYPE"]\0";
  57. const     char *dirfmt = "%lcrw-rw-rw- %3ld %s users %ld %s %s\r\n";    // Used to display directory
  58. const     int ONE = 1;
  59. static    char lockfile[]="T:FTPd.lock";
  60.  
  61. int            errno;                                // Global error var for tcp errors
  62. int            h_errno;                   // Errno for host errors
  63. UBYTE     program_name[256];        // Our own programname
  64. BPTR         confh = -1;                        // Debug window ptr
  65. char        PassiveIP[24];                // For NAT Systems this is the "real" IP to use for passive connects
  66. char        ipbuf[256];             // Will contain the contents from the IPFile
  67. USHORT    ActivePortCounter;        // This will be initialized to the first allowed port or set to 0 for auto-detection
  68. int            rcvbufsz = 16*1024;      // The default SO_RCVBUF size used in setsockopt() calls
  69.  
  70. /*****************************************************************************************
  71.  * PROTOTYPES
  72.  *****************************************************************************************/
  73.  
  74. int         main(int argc, char argv[]);
  75. int            ftpmain(void);
  76. void        CloseLibs(void);
  77. void         fail(long iocode, char *errstring, ...);
  78. long         sendfile(BPTR fp,LONG s,int mode, BOOL sendCRLF);
  79. long         recvfile(BPTR fp,LONG s,int mode);
  80. long         DataSocket(struct FTP *ftp,char *path, short mode);
  81.  
  82. static     void     FTPLogin(struct FTP *ftp, char *pass);
  83. static     int     pport(struct FTP *ftp,char *arg);
  84. static     void     Passive(struct FTP *ftp);
  85. static     void     FTPList(struct FTP *ftp, char *arg);
  86. static     void     ChangeDirectory(struct FTP *ftp, char *arg);
  87. static     long     ShowDirContents(char *arg, BPTR fh,struct FTP *ftp);
  88. static     void     SendTransferStats(long s);
  89. static  void    HandleDownload(struct FTP *ftp,char *arg);
  90. static  void    HandleSize(struct FTP *ftp,char *arg);
  91. static  void  HandleUpload(struct FTP *ftp, char *arg);
  92. static    void    HandleFeatures(struct FTP *ftp);
  93. static     void     HandleClient(struct FTP *ftp, char *arg);
  94. static     void     HandleHelp(struct FTP *ftp, char *arg);
  95. static     void     InitStats(struct FTP *ftp);
  96. static     BOOL     HandleStats(char *actionstring,...);
  97. static     BOOL     RemoveFromStats(void);
  98. static  void    HandleStat(struct FTP *ftp, char *arg);
  99. static     long     CountOnlineUsers(void);
  100.  
  101. /****************************************************************************************
  102.  * FUNCTION: main()
  103.  *  PURPOSE: Main entry point
  104.  *    INPUT: argc => Argument count
  105.  *           argv => Argument array
  106.  *   RETURN: Returncode for shell/inetd (0)
  107.  ****************************************************************************************/
  108.  
  109. int main(int argc, char argv[])
  110.     {
  111.     int         error;
  112.     BPTR        prefsptr;
  113.  
  114.     if(!(IntuitionBase=(struct IntuitionBase *) OpenLibrary("intuition.library",39L)))
  115.         {
  116.         DebugLog("Cannot open intuition.library V39+!!!");
  117.         SetError(ERROR_INVALID_RESIDENT_LIBRARY);
  118.         CloseLibs();
  119.         }
  120.     if(!(SocketBase=(struct Library *) OpenLibrary(SOCKETNAME,4L)))
  121.         {
  122.         fail(ERROR_INVALID_RESIDENT_LIBRARY,"Cannot open %s V4+ - Please start TCP/IP first!!!",SOCKETNAME);
  123.         SetError(ERROR_INVALID_RESIDENT_LIBRARY);
  124.         CloseLibs();
  125.         }
  126.     SysLogBase = OpenLibrary(SYSLOGNAME, SYSLOGVERSION);    // No check required, if it does not exist we simply ignore Log()
  127.     GetProgramName(program_name,sizeof(program_name));
  128.     error = SocketBaseTags(    SBTM_SETVAL(SBTC_ERRNOPTR(sizeof(errno))),    &errno,
  129.                                                     SBTM_SETVAL(SBTC_HERRNOLONGPTR),                        &h_errno,
  130.                                                     SBTM_SETVAL(SBTC_LOGTAGPTR),                                program_name,
  131.                                                     SBTM_SETVAL(SBTC_BREAKMASK),                                SIGBREAKF_CTRL_C,
  132.                                                     TAG_END);
  133.     if(error != 0)
  134.         {
  135.         fail(0,"Could not initialize 'bsdsocket.library' (%ld, %s)",error,tcp_error(error));
  136.         CloseLibs();
  137.         }
  138.     if(!(UtilityBase=(struct Library *) OpenLibrary("utility.library",37L)))
  139.         {
  140.         fail(ERROR_INVALID_RESIDENT_LIBRARY,"Cannot open utility.library V37+!!!");
  141.         SetError(ERROR_INVALID_RESIDENT_LIBRARY);
  142.         CloseLibs();
  143.         }
  144.     if(!(LocaleBase=(struct LocaleBase *)OpenLibrary("locale.library",38L)))
  145.         {
  146.         fail(ERROR_INVALID_RESIDENT_LIBRARY,"Cannot open locale.library V38+!!!");
  147.         SetError(ERROR_INVALID_RESIDENT_LIBRARY);
  148.         CloseLibs();
  149.         }
  150.     if(!(FAMEBase=(struct FAMELibrary *)OpenLibrary(FAMENAME,5L)))
  151.         {
  152.         fail(ERROR_INVALID_RESIDENT_LIBRARY,"Cannot open FAME.library V5++!!!");
  153.         SetError(ERROR_INVALID_RESIDENT_LIBRARY);
  154.     CloseLibs();
  155.         }
  156.     if(!(fib = AllocDosObject(DOS_FIB,NULL)))
  157.         {
  158.         fail(IoErr(),"AllocFIB failed!!!");
  159.         SetError(ERROR_INVALID_RESIDENT_LIBRARY);
  160.     CloseLibs();
  161.         }
  162.     if(!(mem_pool=CreatePool(MEMF_CLEAR|MEMF_PUBLIC,20480L,20480L)))
  163.         {
  164.         fail(ERROR_NO_FREE_STORE,"Mem pool alloc failed!");
  165.         SetError(ERROR_NO_FREE_STORE);
  166.         CloseLibs();
  167.         }
  168.     if(!(readbuf = AllocPooled(mem_pool,CMDBUF_SIZE)))
  169.         {
  170.         fail(ERROR_NO_FREE_STORE,"readbuf alloc failed!!!");
  171.         SetError(ERROR_NO_FREE_STORE);
  172.         CloseLibs();
  173.         }
  174.     if(!(readtmp = AllocPooled(mem_pool,CMDBUF_TEMP)))
  175.         {
  176.         fail(ERROR_NO_FREE_STORE,"readtmp alloc failed!!!");
  177.         SetError(ERROR_NO_FREE_STORE);
  178.         CloseLibs();
  179.         }
  180.     if(!(filebuf = AllocPooled(mem_pool,BLKSIZE)))
  181.         {
  182.         fail(ERROR_NO_FREE_STORE,"filebuf alloc failed!!!");
  183.         SetError(ERROR_NO_FREE_STORE);
  184.         CloseLibs();
  185.         }
  186.     if(!(uspbuf = AllocPooled(mem_pool,CMDBUF_SIZE)))
  187.         {
  188.         fail(ERROR_NO_FREE_STORE,"uspbuf alloc failed!!!");
  189.         SetError(ERROR_NO_FREE_STORE);
  190.         CloseLibs();
  191.         }
  192.     if(!(FameInfo = AllocPooled(mem_pool,sizeof(struct FAMEInfos))))
  193.         {
  194.         fail(ERROR_NO_FREE_STORE,"FameInfo alloc failed!!!");
  195.         SetError(ERROR_NO_FREE_STORE);
  196.         CloseLibs();
  197.         }
  198.     if(!(fstats = AllocPooled(mem_pool,sizeof(struct FTPdStats))))
  199.         {
  200.         fail(ERROR_NO_FREE_STORE,"FTPdStats alloc failed!!!");
  201.         SetError(ERROR_NO_FREE_STORE);
  202.         CloseLibs();
  203.         }
  204.     if(!(tmpptr = AllocPooled(mem_pool,sizeof(struct FTPdStats))))
  205.         {
  206.         fail(ERROR_NO_FREE_STORE,"FTPdStats2 alloc failed!!!");
  207.         SetError(ERROR_NO_FREE_STORE);
  208.         CloseLibs();
  209.         }
  210.     if(!(fconfig = AllocPooled(mem_pool,sizeof(struct FTPdConfig))))
  211.         {
  212.         fail(ERROR_NO_FREE_STORE,"fconfig alloc failed!!!");
  213.         SetError(ERROR_NO_FREE_STORE);
  214.         CloseLibs();
  215.         }
  216.     if(prefsptr=Open(prefspath,MODE_OLDFILE))
  217.         {
  218.         Read(prefsptr,fconfig,sizeof(struct FTPdConfig));
  219.         Close(prefsptr);
  220.         }
  221.     else
  222.         {
  223.     FAMEStrCopy("RAM:",fconfig->UploadTempPath,255);        // Default Upload path is RAM:
  224.         fconfig->FileNameLength = 12;                       // Default length is 12
  225.         }
  226.     if(!fconfig->FileBufferSize) fconfig->FileBufferSize = 512;    // Set to 512k copy buffer if not defined
  227.     if(fconfig->Flags1 & CFG_USEDEBUG)
  228.         {
  229.         if(!(confh = Open("CON:0/0/680/250/FTPOUT/CLOSE/WAIT",MODE_NEWFILE)))
  230.             {
  231.         CloseLibs();
  232.             }
  233.         }
  234.     if(!fconfig->Timeout) fconfig->Timeout = 600;                    // Default timeout is 10minutes (600s)
  235.     if(*fconfig->IPFile)
  236.         {
  237.         if(prefsptr = Open(fconfig->IPFile,MODE_OLDFILE))
  238.             {
  239.         FGets(prefsptr,ipbuf,CMDBUF_SIZE);
  240.             Close(prefsptr);
  241.             if(strlen(ipbuf) > 2)
  242.                 {
  243.           if(ipbuf[strlen(ipbuf)-1] == '\n')
  244.                     {
  245.                     ipbuf[strlen(ipbuf)-1] = '\0';
  246.                     }
  247.                 }
  248.             else
  249.                 {
  250.         *ipbuf = '\0';
  251.                 }
  252.       }
  253.         else
  254.             {
  255.             *ipbuf = '\0';
  256.       }
  257.         }
  258.     else
  259.         {
  260.     *ipbuf = '\0';
  261.         }
  262.     if(fconfig->PortLo != 0 && fconfig->PortHi != 0)
  263.         {
  264.     ActivePortCounter = fconfig->PortLo;                    // Initialize Port counter to start val
  265.         }
  266.     else
  267.         {
  268.         ActivePortCounter = 0;                                                // Let the system decide
  269.         }
  270.   NewList((struct List *)&filelist);        // Initialize the FileList structure
  271.     myloc=OpenLocale(NULL);
  272.     DebugLog("***** FAME-FTPd v%s started. (%08lx) *****\n",COMPILE_VERSION,FindTask(NULL));
  273.     ftpmain();
  274.     if(fconfig->Flags1 & CFG_WEEKTOP)
  275.         {
  276.         WeektopStats();
  277.         }
  278.     DebugLog("***** FAME-FTPd v%s stopped. (%08lx) *****\n",COMPILE_VERSION,FindTask(NULL));
  279.     CloseLibs();
  280.     }
  281.  
  282. /************************************************************************************************
  283.  * FUNCTION: ftpmain()
  284.  *  PURPOSE: Main loop, all TCP/IP communication is handled here
  285.  *    INPUT: -
  286.  *   RETURN: -
  287.  ************************************************************************************************/
  288.  
  289. int ftpmain(void)
  290.     {
  291.     fd_set    readfds;
  292.     struct    sockaddr_in peer;
  293.     long        cnt,peerlen = sizeof(peer);
  294.     long        addrlen;
  295.     int            rc;
  296.     struct    FTP *myftp;
  297.     char         **cmdp,*arg;
  298.   BOOL        end = FALSE;
  299.     struct    timeval ftptimeout;
  300.     BPTR        titleptr;
  301.     struct  hostent *iphost;
  302.     LONG      ipinfo;
  303.  
  304.     server_socket = init_inet_daemon();
  305.   if(server_socket == -1)
  306.         {
  307.         fail(0,"Invalid socket - Maybe not started from inetD?!");
  308.         return(-1);
  309.         }
  310.     if(!(myftp = AllocPooled(mem_pool,sizeof(struct FTP))))
  311.         {
  312.         fail(ERROR_NO_FREE_STORE,"myftp alloc failed!!!");
  313.         return(-2);
  314.         }
  315.     myftp->data         = -1;
  316.     myftp->pdata         = -1;
  317.   myftp->control    = server_socket;
  318.     FAMEFillMem(&peer,0,sizeof(struct sockaddr_in));
  319.     getpeername(server_socket,(struct sockaddr *)&myftp->port,&peerlen);
  320.     myftp->port.sin_port = IPPORT_FTPD;
  321.   addrlen = sizeof(myftp->ctrl);
  322.   if (getsockname(server_socket, (struct sockaddr *) &myftp->ctrl, &addrlen) < 0)
  323.         {
  324.         fail(0,"getsockname(): %s (%ld)",tcp_error(Errno()),Errno());
  325.         usprintf(server_socket,CRLF_NOSTRIP,ftperror);
  326.         return(-2);
  327.     }
  328.   FAMEStrCopy(Inet_NtoA(myftp->port.sin_addr.s_addr),myftp->IPaddr,21);
  329.     if(RetrieveFAMEInfos())
  330.         {
  331.         fail(0,"Cannot connect to FAME, please start BBS System first !!!");
  332.         usprintf(server_socket,CRLF_NOSTRIP,ftperror);
  333.         return(-3);
  334.         }
  335.     if(fconfig->Flags1 & CFG_USEDNS)
  336.         {
  337.         if(!DNSLookUp(&myftp->port,myftp->hostname)) DebugLog("Connection from %s (%s) accepted.",myftp->hostname,myftp->IPaddr);
  338.         else DebugLog("Connection from %s accepted",myftp->IPaddr);
  339.     }
  340.     else
  341.         {
  342.         DebugLog("Connection from %s accepted",myftp->IPaddr);
  343.         }
  344.     if(*ipbuf!='\0')    // We have a valid IP/Hostname, try to resolve it:
  345.         {
  346.         iphost = gethostbyname(ipbuf);
  347.         if(iphost)
  348.             {
  349.       memcpy( &ipinfo, &iphost->h_addr_list[ 0 ][ 0 ], 4 );
  350.       FAMEStrCopy(Inet_NtoA(ipinfo),PassiveIP,24);
  351.             }
  352.     else
  353.             {
  354.             fail(0,"Unable to resolve %s !!!",ipbuf);
  355.             SetError(ERROR_OBJECT_NOT_FOUND);
  356.             return(-4);
  357.             }
  358.         }
  359.     if(fconfig->MaxUsers)            // We have to check how many users are currently connected:
  360.         {
  361.         cnt = CountOnlineUsers();
  362.         if(cnt >= fconfig->MaxUsers)
  363.             {
  364.             usprintf(server_socket,CRLF_NOSTRIP,"421 Maximum usercount exceeded! Please try again l8er.\r\n");
  365.             shutdown(myftp->control,2);
  366.             CloseSocket(myftp->control);
  367.             server_socket = -1;
  368.             return(0);
  369.             }
  370.         }
  371.     usprintf(server_socket,CRLF_NOSTRIP,banner,FameInfo->BBSName,FameInfo->FAMEVersion,FameInfo->FAMERevision,COMPILE_VERSION,COMPILE_BUILD);
  372.     if(*fconfig->TitleFile)
  373.         {
  374.         if(titleptr = Open(fconfig->TitleFile,MODE_OLDFILE))
  375.             {
  376.             while(FGets(titleptr,readbuf,CMDBUF_SIZE))
  377.                 {
  378.         usprintf(myftp->control,CRLF_STRIP,"220- %s",readbuf);
  379.                 }
  380.             Close(titleptr);
  381.             }
  382.         }
  383.     usprintf(server_socket,CRLF_NOSTRIP,"220 \r\n");
  384.     InitStats(myftp);
  385.     HandleStats("Connection from %s",myftp->IPaddr);
  386.     FD_ZERO(&readfds);
  387.     ftptimeout.tv_secs = fconfig->Timeout;
  388.     ftptimeout.tv_micro = 0;
  389.     // Main FTP loop starts here
  390.  
  391.     for(;;)
  392.         {
  393.          FD_SET(server_socket,&readfds);
  394.        rc = WaitSelect(server_socket+1,&readfds,NULL,NULL,&ftptimeout,NULL);
  395.         if(rc < 0) break;
  396.         if(!rc)
  397.             {
  398.             usprintf(myftp->control,CRLF_NOSTRIP,bye);
  399.             DebugLog("Timeout recieved for %s, exiting.",myftp->IPaddr);
  400.             break;
  401.             }
  402.         FAMEFillMem(readbuf,0UL,CMDBUF_SIZE);
  403.         if(!FD_ISSET(server_socket,&readfds))
  404.             {
  405.             break;
  406.             }
  407.         cnt = readline(server_socket,readbuf,CMDBUF_SIZE);
  408.         if(cnt<=0)
  409.             {
  410.             break;
  411.         }
  412.         CutCRLF(readbuf);
  413.  
  414.         if(Strnicmp(readbuf,"PASS",4)) 
  415.             {
  416.             if(fconfig->Flags1 & CFG_USEDEBUG)
  417.                 {
  418.                 DebugLog("readbuf=|%s|",readbuf);
  419.               }
  420.             }
  421.  
  422.        /* Find command in table; if not present, return syntax error */
  423.  
  424.        for(cmdp=commands;*cmdp != NULL;cmdp++)
  425.             {
  426.             if(!Strnicmp(*cmdp,readbuf,strlen(*cmdp))) break;
  427.             }
  428.        if(*cmdp == NULL)
  429.             {
  430.            usprintf(myftp->control,CRLF_NOSTRIP,badcmd);
  431.            continue;
  432.            }
  433.         if(*myftp->username=='\0' || *myftp->password=='\0')
  434.             {
  435.              switch(cmdp-commands)
  436.                 {
  437.                  case CMD_USER:
  438.                  case CMD_PASS:
  439.                  case CMD_QUIT:    break;
  440.                  default:                usprintf(myftp->control,CRLF_NOSTRIP,notlog);
  441.                                                  continue;
  442.                  }
  443.             }
  444.        arg = &readbuf[strlen(*cmdp)];
  445.        while(*arg == ' ') arg++;
  446.         switch(cmdp-commands)
  447.             {
  448.            case CMD_QUIT:  SendTransferStats(myftp->control);
  449.                                             usprintf(myftp->control,CRLF_NOSTRIP,bye);
  450.                       end = TRUE;
  451.                                             break;
  452.  
  453.             case CMD_USER:    FAMEStrCopy(arg,myftp->username,31);
  454.                                             if(*myftp->username=='\0')
  455.                                                 {
  456.                         usprintf(myftp->control,CRLF_NOSTRIP,"332- Need account for login.\r\n");
  457.                                                 }
  458.                                             else
  459.                                                 {
  460.                                                 usprintf(myftp->control,CRLF_NOSTRIP,givepass);
  461.                                                 }
  462.                                             break;
  463.  
  464.             case CMD_PASS:    if(*myftp->username=='\0')
  465.                                                 {
  466.                                                 usprintf(myftp->control,CRLF_NOSTRIP,userfirst);
  467.                                       }
  468.                                             else
  469.                                         {
  470.                         FTPLogin(myftp,arg);
  471.                                                 }
  472.                                             break;
  473.  
  474.             case CMD_SYST:    usprintf(myftp->control,CRLF_NOSTRIP,systreply);
  475.                                             break;
  476.  
  477.            case CMD_PORT:    if(pport(myftp,arg) == -1) usprintf(myftp->control,CRLF_NOSTRIP,badport);
  478.                                            else usprintf(myftp->control,CRLF_NOSTRIP,portok);
  479.                                            break;
  480.  
  481.             case CMD_NOOP:    usprintf(myftp->control,CRLF_NOSTRIP,okay);
  482.                       break;
  483.  
  484.            case CMD_TYPE:    switch(arg[0])
  485.                                                {
  486.                                                case 'A':
  487.                                                case 'a': myftp->type = ASCII_TYPE;                                    /* ASCII */
  488.                                                                    usprintf(myftp->control,CRLF_NOSTRIP,typeok,arg);
  489.                                                                    break;
  490.  
  491.                                                case 'l':
  492.                                                case 'L': while(*arg != ' ' && *arg != '\0') arg++;    /* LOGICAL */
  493.                                                                    if(*arg == '\0' || *++arg != '8')
  494.                                                                        {
  495.                                                                        usprintf(myftp->control,CRLF_NOSTRIP,only8);
  496.                                                                        break;
  497.                                                                        }
  498.                                                                    myftp->type = LOGICAL_TYPE;
  499.                                                                    myftp->logbsize = 8;
  500.                                                                    usprintf(myftp->control,CRLF_NOSTRIP,typeok,arg);
  501.                                                                    break;
  502.  
  503.                                                case 'B':
  504.                                                case 'b':
  505.                                                case 'I':
  506.                                                case 'i': myftp->type = IMAGE_TYPE;                                                            /* BINARY/IMAGE */
  507.                                                                    usprintf(myftp->control,CRLF_NOSTRIP,typeok,arg);
  508.                                                                    break;
  509.  
  510.                                                default:  usprintf(myftp->control,CRLF_NOSTRIP,badtype,arg);        /* INVALID TYPE */
  511.                                                                    break;
  512.                                                }
  513.                                            break;
  514.  
  515.             case CMD_PASV:    Passive(myftp);
  516.                                             break;
  517.  
  518.             case CMD_PWD:
  519.             case CMD_XPWD:  usprintf(myftp->control,CRLF_NOSTRIP,pwdmsg,myftp->cd);
  520.                                            break;
  521.  
  522.             case CMD_CWD:
  523.             case CMD_XCWD:    ChangeDirectory(myftp,arg);
  524.                                             break;
  525.  
  526.       case CMD_CDUP:    ChangeDirectory(myftp,"..");
  527.                                             break;
  528.  
  529.             case CMD_LIST:    FTPList(myftp,arg);
  530.                       break;
  531.  
  532.             case CMD_RETR:    HandleDownload(myftp,arg);
  533.                       break;
  534.  
  535.             case CMD_SIZE:  HandleSize(myftp,arg);
  536.                                             break;
  537.  
  538.       case CMD_STOR:    HandleUpload(myftp,arg);
  539.                                             break;
  540.  
  541.             case CMD_STRU:    if(!Strnicmp("F",arg,1)) usprintf(myftp->control,CRLF_NOSTRIP,stru_ok);
  542.                                             else usprintf(myftp->control,CRLF_NOSTRIP,stru_fail);
  543.                                             break;
  544.  
  545.             case CMD_MODE:  if(!Strnicmp("S",arg,1)) usprintf(myftp->control,CRLF_NOSTRIP,mode_ok);
  546.                                             else usprintf(myftp->control,CRLF_NOSTRIP,mode_fail);
  547.                                             break;
  548.  
  549.             case CMD_ABOR:    if(myftp->pdata!=-1)
  550.                                                 {
  551.                                                 shutdown(myftp->pdata,2);
  552.                                                 CloseSocket(myftp->pdata);
  553.                                                 myftp->pdata = -1;
  554.                                                 }
  555.                                             if(myftp->data!=-1)
  556.                                                 {
  557.                                                 shutdown(myftp->data,2);
  558.                                                 CloseSocket(myftp->data);
  559.                                                 myftp->data = -1;
  560.                                                 }
  561.                       usprintf(myftp->control,CRLF_NOSTRIP,abor_ok);
  562.                                             break;
  563.  
  564.             case CMD_FEAT:    HandleFeatures(myftp);
  565.                                             break;
  566.  
  567.             case CMD_CLNT:    HandleClient(myftp,arg);
  568.                                             break;
  569.  
  570.             case CMD_HELP:    HandleHelp(myftp,arg);
  571.                                             break;
  572.  
  573.             case CMD_STAT:    HandleStat(myftp,arg);
  574.                       break;
  575.  
  576.             default:                HandleStats("User is idle");
  577.                                             usprintf(myftp->control,CRLF_NOSTRIP,badcmd);
  578.                       break;
  579.  
  580.             }
  581.         if(end==TRUE) break;
  582.         }
  583.     RemoveFromStats();
  584.     if(myftp->pdata!=-1)
  585.         {
  586.     shutdown(myftp->pdata,2);
  587.         CloseSocket(myftp->pdata);
  588.         myftp->pdata=-1;
  589.         }
  590.     if(myftp->data!=-1)
  591.         {
  592.     shutdown(myftp->data,2);
  593.         CloseSocket(myftp->data);
  594.         myftp->data=-1;
  595.         }
  596.     if(end==FALSE)
  597.         {
  598.         SendTransferStats(-1);        // We where kicked out, log transfer stats
  599.         }
  600.     shutdown(myftp->control,2);
  601.     CloseSocket(myftp->control);
  602.     server_socket = -1;
  603.     return(0);
  604.     }
  605.  
  606. /************************************************************************************************
  607.  * FUNCTION: FTPLogin()
  608.  *  PURPOSE: Handles FTP Login (username must be in ftp->username, pass in *pass)
  609.  *    INPUT: ftp    => Master FTP structure
  610.  *           pass    => Supplied userpassword
  611.  ************************************************************************************************/
  612.  
  613. static void FTPLogin(struct FTP *ftp, char *pass)
  614.     {
  615.     if(ValidateFAMEUser(ftp->username,pass,ftp)==FALSE)
  616.         {
  617.         usprintf(ftp->control,CRLF_NOSTRIP,noperm);
  618.         *ftp->username='\0';
  619.         *ftp->password='\0';
  620.         return;
  621.         }
  622.   else
  623.         {
  624.         if(CheckIfOnline(ftp->usernumber)==TRUE)
  625.             {
  626.       usprintf(ftp->control,CRLF_NOSTRIP,onlinewarn);
  627.       *ftp->username='\0';
  628.             *ftp->password='\0';
  629.       return;
  630.             }
  631.         FAMEStrCopy(pass,ftp->password,31);
  632.         usprintf(ftp->control,CRLF_NOSTRIP,logged,ftp->username,"proceed.");
  633.         DebugLog("LOGIN: User %s (%ld) successfully connected.",ftp->username,ftp->usernumber);
  634.         }
  635.     FAMEStrCopy("/",ftp->cd,255);            // Set default current directory to "/"
  636.     ftp->type = ASCII_TYPE;                        // Set default transfer mode to ASCII
  637.     fstats->UserNumber = ftp->usernumber;
  638.     HandleStats("Successfully logged in",ftp->username);
  639.     }
  640.  
  641. /************************************************************************************************
  642.  * FUNCTION: pport()
  643.  *  PURPOSE: Handles FTP command PORT
  644.  *    INPUT: ftp => Our Master FTP Structure
  645.  *           arg => Port Args (IP + Port)
  646.  *   RETURN: 0 = Success, -1 = Illegal Syntax in Port Command
  647.  ************************************************************************************************/
  648.  
  649. static int pport(struct FTP *ftp,char *arg)
  650.     {
  651.     long n;
  652.     long i;
  653.  
  654.     n = 0;
  655.     for(i=0;i<4;i++)
  656.         {
  657.         n = FAMEAtol(arg) + (n << 8);
  658.         if((arg = FAMEStrChr(arg,',')) == NULL) return -1;
  659.         arg++;
  660.         }
  661.     ftp->port.sin_addr.s_addr = n;
  662.     n = FAMEAtol(arg);
  663.     if((arg = FAMEStrChr(arg,',')) == NULL)    return -1;
  664.     arg++;
  665.     n = FAMEAtol(arg) + (n << 8);
  666.     if(!n) return -1;
  667.     ftp->port.sin_port = n;
  668.     if(ftp->pdata!=-1)
  669.         {
  670.         CloseSocket(ftp->pdata);
  671.         ftp->pdata = -1;
  672.         }
  673.     return 0;
  674.     }
  675.  
  676. /*************************************************************************************************
  677.  * FUNCTION: Passive()
  678.  *  PURPOSE: Toggles Passive FTP Mode (PASV)
  679.  *    INPUT: *ftp => Master FTP structure
  680.  *   RETURN: -
  681.  *     NOTE: Result is stored in ftp->pdata & ftp->pasv!
  682.  *************************************************************************************************/
  683.  
  684. static void Passive(struct FTP *ftp)
  685.     {
  686.     LONG             len,err;
  687.     register     char *p,*a;
  688.     ULONG         nataddress = 0UL;
  689.  
  690.     if(ftp->pdata != -1)        // For safety, as it may be possible to call it twice!
  691.         {
  692.         CloseSocket(ftp->pdata);
  693.         ftp->pdata = -1;
  694.         }
  695.     ftp->pdata = socket(AF_INET, SOCK_STREAM, 0);
  696.     if (ftp->pdata < 0)
  697.         {
  698.         usprintf(ftp->control,CRLF_NOSTRIP,nopasv,1);
  699.         return;
  700.         }
  701.   setsockopt(ftp->pdata, SOL_SOCKET, SO_RCVBUF, (char *)&rcvbufsz, sizeof(rcvbufsz) );
  702.     ftp->pasv = ftp->ctrl;
  703.     if(ActivePortCounter!=0)                                                // We must choose the port from our range
  704.         {
  705.         ftp->pasv.sin_port = ActivePortCounter;                // Use our own port counter
  706.         ActivePortCounter++;
  707.         if(ActivePortCounter >= fconfig->PortHi) ActivePortCounter = fconfig->PortLo;
  708.         }
  709.     else
  710.         {
  711.         ftp->pasv.sin_port = 0;                                                // Let the stack decide
  712.         }
  713.     if (bind(ftp->pdata, (struct sockaddr *) &ftp->pasv, sizeof(ftp->pasv)) >= 0)
  714.         {
  715.         len = sizeof(ftp->pasv);
  716.         if (getsockname(ftp->pdata, (struct sockaddr *) &ftp->pasv, &len) >= 0)
  717.             {
  718.             if (listen(ftp->pdata, 1) >= 0)
  719.                 {
  720.                 a = (char *) &ftp->pasv.sin_addr;
  721.                 p = (char *) &ftp->pasv.sin_port;
  722.                 if(*PassiveIP)
  723.                     {
  724.                     nataddress = inet_addr(PassiveIP);
  725.                     a = (char *) &nataddress;
  726.                     }
  727.                 usprintf(ftp->control,CRLF_NOSTRIP,pasvcon,UC(a[0]),UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
  728.                 return;
  729.                 }
  730.             else err = 4;
  731.             }
  732.         else err = 3;
  733.         }
  734.     else err = 2;
  735.     DebugLog("Passive(): TCP Error %ld (%s)",Errno(),tcp_error(Errno()));
  736.     CloseSocket(ftp->pdata);
  737.     ftp->pdata = -1;
  738.     usprintf(ftp->control,CRLF_NOSTRIP,nopasv,err);
  739.     }
  740.  
  741. /************************************************************************************************
  742.  * FUNCTION: ChangeDirectory()
  743.  *  PURPOSE: Handles FTP command CWD/XCWD
  744.  *    INPUT: *ftp => Pointer to Master FTP structure
  745.  *           *arg => Argument to which we have to change dir
  746.  *   RETURN: -
  747.  ************************************************************************************************/
  748.  
  749. static void ChangeDirectory(struct FTP *ftp, char *arg)
  750.     {
  751.     struct     FConf *f = fconf1;
  752.  
  753.     if(!Stricmp(arg,"..") || !Stricmp(arg,"/"))
  754.         {
  755.     FAMEStrCopy("/",ftp->cd,255);
  756.         usprintf(ftp->control,CRLF_NOSTRIP,cwdmsg,"/");
  757.         fstats->CurrentConf = 0;
  758.         HandleStats("Joined root directory");
  759.         return;
  760.         }
  761.     if(*arg=='/') arg++;
  762.     while(f)
  763.     {
  764.         if(!Strnicmp(f->ConfName,arg,strlen(f->ConfName)))
  765.             {
  766.             FAMEStrCopy(f->ConfName,ftp->cd,255);
  767.             FAMEStrCat("/",ftp->cd);
  768.             usprintf(ftp->control,CRLF_NOSTRIP,cwdmsg,ftp->cd);
  769.             fstats->CurrentConf = f->ConfNumber;
  770.             HandleStats("Joined conf %s", f->ConfName);
  771.             return;
  772.             }
  773.         f=f->next;
  774.         }
  775.     usprintf(ftp->control,CRLF_NOSTRIP,nodir,arg);
  776.     fstats->CurrentConf = 0;
  777.     }
  778.  
  779. /************************************************************************************************
  780.  * FUNCTION: FTPList()
  781.  *  PURPOSE: Handles FTP command LIST including Parameters
  782.  *    INPUT: *ftp => Master FTP structure
  783.  *           *arg => The Path to list
  784.  ************************************************************************************************/
  785.  
  786. static void FTPList(struct FTP *ftp, char *arg)
  787.     {
  788.     BPTR        fh;
  789.   long        total,datcon=NULL,rc;
  790.     char    myfname[256],path[256];
  791.  
  792.     SPrintf(myfname,"T:FAME-FTPd.%08lx",FindTask(NULL));
  793.   if(!(fh = Open(myfname,MODE_READWRITE)))
  794.         {
  795.         usprintf(ftp->control,CRLF_NOSTRIP,noconn);
  796.         return;
  797.         }
  798.     if(*arg=='\0') FAMEStrCopy(ftp->cd,path,255);
  799.     else
  800.         {
  801.         if(!Stricmp(arg,"-l") || !Stricmp(arg,"-la") || !Stricmp(arg,"-al")) FAMEStrCopy(ftp->cd,path,255);
  802.         else FAMEStrCopy(arg,path,255);
  803.         }
  804.     if(!Stricmp(path,"..")) FAMEStrCopy("/",path,255);        // We have only one level of directory, so up means always root
  805.     if(ShowDirContents(path,fh,ftp))
  806.         {
  807.     Close(fh);
  808.         DeleteFile(myfname);
  809.         usprintf(ftp->control,CRLF_NOSTRIP,nodir,path);
  810.         DebugLog("ERROR: List Dir failed: %s",path);
  811.         return;
  812.     }
  813.     Flush(fh);
  814.     rc = DataSocket(ftp,path,0);
  815.   switch(rc)
  816.         {
  817.         case    0:    datcon = ftp->pdata;
  818.                             break;
  819.         case    1:    datcon = ftp->data;
  820.                             break;
  821.         case    -1:    Close(fh);
  822.                             DeleteFile(myfname);
  823.                             return;
  824.         }
  825.     Seek(fh,0L,OFFSET_BEGINNING);
  826.     total = sendfile(fh,datcon,ftp->type,FALSE);
  827.     if(total == -1)        /* An error occurred on the data connection */
  828.         {
  829.         DebugLog("FTPList/Sendfile: %ld",total);
  830.         usprintf(ftp->control,CRLF_NOSTRIP,noconn);
  831.         }
  832.     else     usprintf(ftp->control,CRLF_NOSTRIP,txok, total);
  833.     Close(fh);
  834.     CloseSocket(datcon);
  835.     if(!rc) ftp->pdata = -1;
  836.     else ftp->data = -1;
  837.     DeleteFile(myfname);
  838.     }
  839.  
  840. /**************************************************************************************************
  841.  * FUNCTION: ShowDirContents()
  842.  *  PURPOSE: Displays directory contents for a given conference
  843.  *    INPUT: arg => Path to show
  844.  *           fh  => Filehandle where to print the dir
  845.  *   RETURN: 0 = Success | 1 = Failure
  846.  **************************************************************************************************/
  847.  
  848. static long ShowDirContents(char *arg, BPTR fh, struct FTP *ftp)
  849.     {
  850.     struct    FConf *f;
  851.     char        datebuf[LEN_DATSTRING*2];
  852.     struct    FTPUploads *f1;
  853.  
  854.     FormatStamp(NULL,datebuf,myloc,TRUE);
  855.     f=fconf1;
  856.     if(!Stricmp(arg,"/"))        // Rootdir requested, dump out all available conferences
  857.         {
  858.         while(f)
  859.             {
  860.             FPrintf(fh,dirfmt,'d',1,FameInfo->SysOp,0,datebuf,f->ConfName);
  861.             f=f->next;
  862.             }
  863.         return(0);
  864.         }
  865.  
  866.     // Other directory requested, check if we can find the desired one
  867.  
  868.     while(f)
  869.         {
  870.        if(!Strnicmp(f->ConfName,arg,strlen(f->ConfName)))
  871.             {
  872.             if(*fconfig->HowToUploadFile!='\0')
  873.                 {
  874.                 FPrintf(fh,dirfmt,'-',1,FameInfo->SysOp,GetFileSize(fconfig->HowToUploadFile),datebuf,FilePart(fconfig->HowToUploadFile));
  875.                 }
  876.  
  877.   // Now list all uploaded files for this conference
  878.  
  879.           for(f1=(struct FTPUploads *)filelist.mlh_Head;f1!=(struct FTPUploads *)&filelist.mlh_Tail;f1=(struct FTPUploads *)f1->Node.mln_Succ)
  880.                  {
  881.                 if(f1->ConfNum == f->ConfNumber)
  882.                     {
  883.                     FPrintf(fh,dirfmt,'-',1,ftp->username,f1->FileSize,f1->FileDate,f1->FileName);
  884.                     }
  885.                 }
  886.             return(0);
  887.             }
  888.         f=f->next;
  889.         }
  890.     return(1);
  891.     }
  892.  
  893. /**************************************************************************************************
  894.  * FUNCTION: DataSocket()
  895.  *  PURPOSE: Returns the actual data socket to use:
  896.  *    INPUT: ftp  => Master FTP structure
  897.  *           path => Path to show in control message
  898.  *           mode => TRUE = Filesize will be added | FALSE = Only filename or path is shown
  899.  *   RETURN:  0 => Use ftp->pdata connection
  900.  *            1 => Use ftp->data connection
  901.  *           -1 => Error
  902.  **************************************************************************************************/
  903.  
  904. long DataSocket(struct FTP *ftp,char *path, short mode)
  905.     {
  906.     struct     sockaddr_in dport;
  907.     long        fsize;
  908.     long        retry = 0;
  909.  
  910.     if(ftp->pdata >=0)
  911.         {
  912.         struct sockaddr_in from;
  913.     LONG s, fromlen = sizeof(from);
  914.  
  915.     FAMEFillMem(&from,0,sizeof(struct sockaddr_in));
  916.         s = accept(ftp->pdata,(struct sockaddr *) &from, &fromlen);
  917.         if(s < 0)
  918.             {
  919.             usprintf(ftp->control,CRLF_NOSTRIP,noopendata);
  920.             CloseSocket(ftp->pdata);
  921.             ftp->pdata = -1;
  922.             return(-1);
  923.       }
  924.         if(mode)
  925.             {
  926.       fsize = GetFileSize(path);
  927.             usprintf(ftp->control,CRLF_NOSTRIP,filesend,ftp->type == ASCII_TYPE ? "ASCII" : "BINARY",FilePart(path),fsize);
  928.       }
  929.         else
  930.             {
  931.             usprintf(ftp->control,CRLF_NOSTRIP,sending,ftp->type == ASCII_TYPE ? "ASCII" : "BINARY",path);
  932.             }
  933.         CloseSocket(ftp->pdata);
  934.         ftp->pdata = s;
  935.         return(0);
  936.         }
  937.  
  938.   if(ftp->data >=0)
  939.         {
  940.     usprintf(ftp->control,CRLF_NOSTRIP,"125 Using existing data connection for %s.\r\n",path);
  941.         return(1);
  942.         }
  943.  
  944.     if(mode)
  945.         {
  946.     fsize = GetFileSize(path);
  947.         usprintf(ftp->control,CRLF_NOSTRIP,filesend,ftp->type == ASCII_TYPE ? "ASCII" : "BINARY",FilePart(path),fsize);
  948.         }
  949.     else
  950.         {
  951.         usprintf(ftp->control,CRLF_NOSTRIP,sending,ftp->type == ASCII_TYPE ? "ASCII" : "BINARY",path);
  952.         }
  953.     FAMEFillMem(&dport,0,sizeof(struct sockaddr_in));
  954.     ftp->data = socket(AF_INET,SOCK_STREAM,0);
  955.   setsockopt(ftp->data, SOL_SOCKET, SO_RCVBUF, (char *)&rcvbufsz, sizeof(rcvbufsz) );
  956.     dport.sin_family            =    AF_INET;
  957.     dport.sin_addr.s_addr    =    ftp->port.sin_addr.s_addr;
  958.     dport.sin_port                =    ftp->port.sin_port;
  959.   while(connect(ftp->data,(struct sockaddr *)&ftp->port,sizeof(struct sockaddr_in)) < 0)
  960.         {
  961.         if(Errno()==EADDRINUSE || errno == EINTR && retry < CONNECT_RETRY)
  962.             {
  963.             DebugLog("DataSocket(): connect() failed in retry %ld with code %ld.",retry,Errno());
  964.             retry++;
  965.             Delay(CONNECT_WAIT);
  966.       continue;
  967.           }
  968.         DebugLog("DataSocket->connect(): TCP Error %ld (%s)",Errno(),tcp_error(Errno()));
  969.         CloseSocket(ftp->data);
  970.         ftp->data = -1;
  971.         usprintf(ftp->control,CRLF_NOSTRIP,noopendata);
  972.         return(-1);
  973.         }
  974.     return(1);
  975.     }
  976.  
  977. /**************************************************************************************************
  978.  * FUNCTION: sendfile()
  979.  *  PURPOSE: Send a file (opened by caller) on a network socket
  980.  *    INPUT:   fp         => Filepointer to already opened file
  981.  *              s         => Socket to send file to
  982.  *           mode         => Transfer Mode (ASCII/BINARY)
  983.  *           sendCRLF => TRUE = Send CRLF combination with buffered check, FALSE = ignore CRLF sending
  984.  *   RETURN:   -1         => Error occured
  985.  *           <>-1         => Amount of bytes sent
  986.  **************************************************************************************************/
  987.  
  988. long sendfile(BPTR fp,LONG s,int mode, BOOL sendCRLF)
  989.     {
  990.     long     total = 0;
  991.     long     cnt;
  992.     char    *asciibuf;
  993.  
  994.     if(!GetFileSizeFH(fp)) return(0);
  995.     switch(mode)
  996.         {
  997.         default:
  998.         case LOGICAL_TYPE:
  999.         case IMAGE_TYPE:        for(;;)
  1000.                                                     {
  1001.                                                     SetIoErr(0);
  1002.                                                     cnt = Read(fp,filebuf,BLKSIZE);
  1003.                                                     if(!cnt)
  1004.                                                         {
  1005.                             cnt=IoErr();
  1006.                                                         if(cnt) DebugLog("sendfile(): IoErr() => %ld - Total => %ld!",cnt,total);
  1007.                                                         break;
  1008.                                                         }
  1009.                                                     total += cnt;
  1010.                                                     if(send(s,filebuf,cnt,0) == -1) return(-1);
  1011.                                                     }
  1012.                                                 break;
  1013.  
  1014.         case ASCII_TYPE:    if(!(asciibuf = AllocPooled(mem_pool, BLKSIZE))) return(-1);
  1015.                                                 while(1)
  1016.                                                     {
  1017.                                                     if(!FGets(fp,asciibuf,BLKSIZE))
  1018.                                                         {
  1019.                                                         cnt = IoErr();
  1020.                             if(cnt)
  1021.                                                             {
  1022.                                                             DebugLog("sendfile(): IoErr() => %ld - Total => %ld!",cnt,total);
  1023.                               return(-1);
  1024.                               }
  1025.                                                         else 
  1026.                                                             {
  1027.                                                             break;
  1028.                                                             }
  1029.                             }
  1030.                                                     if(sendCRLF==TRUE)
  1031.                                                         {
  1032.                               CutCRLF(asciibuf);
  1033.                                                         FAMEStrCat("\n\r",asciibuf);
  1034.                                                         }
  1035.                                         cnt = send(s,asciibuf,strlen(asciibuf),0);
  1036.                                                     if(cnt==-1) return(-1);
  1037.                           total +=cnt;
  1038.                                                     }
  1039.                                                 FreePooled(mem_pool,asciibuf,BLKSIZE);
  1040.                                                 break;
  1041.  
  1042.         }
  1043.     return(total);
  1044.     }
  1045.  
  1046. /**************************************************************************************************
  1047.  * FUNCTION: recvfile()
  1048.  *  PURPOSE: Recieve a file (opened by caller) from a network socket
  1049.  *    INPUT:   fp => Filepointer to already opened and writeable file
  1050.  *              s => Socket to recieve file from
  1051.  *           mode => Transfer Mode (ASCII/BINARY)
  1052.  *   RETURN:   -1 => Error occured
  1053.  *           <>-1 => Amount of bytes recieved
  1054.  **************************************************************************************************/
  1055.  
  1056. long recvfile(BPTR fp,LONG s,int mode)
  1057.     {
  1058.     int     cnt;
  1059.     long    total=0;
  1060.     UBYTE    ascbuf[2];
  1061.  
  1062.     switch(mode)
  1063.         {
  1064.         default:
  1065.         case LOGICAL_TYPE:
  1066.         case IMAGE_TYPE:        for(;;)
  1067.                                                     {
  1068.                                                     FAMEFillMem(filebuf,0,BLKSIZE);
  1069.                           cnt = recv(s,filebuf,BLKSIZE,0);
  1070.                           if(cnt==-1)
  1071.                                                         {
  1072.                             return(-1);
  1073.                                                         }
  1074.                           if(!cnt) break;
  1075.                                                     total+=cnt;
  1076.                                                     if(Write(fp,filebuf,cnt)!=cnt)
  1077.                                                         {
  1078.                                                         if(IoErr())
  1079.                                                             {
  1080.                                                             DebugLog("Binary-Write() failed with IOErr=%ld",IoErr());
  1081.                                                             return(-1);
  1082.                                 }
  1083.                             else break;
  1084.                                                         }
  1085.                                                     }
  1086.                                                 break;
  1087.  
  1088.         case ASCII_TYPE:        for(;;)
  1089.                                                     {
  1090.                           cnt = recv(s,&ascbuf[0],1,0);
  1091.                                                     ascbuf[1] = '\0';
  1092.                           if(!cnt) break;
  1093.                                                     if(cnt==-1) return(-1);
  1094.                                                     total+=cnt;
  1095.                           if(FPutC(fp,(ULONG)ascbuf[0])==ENDSTREAMCH)
  1096.                                                         {
  1097.                                                         return(-1);
  1098.                                }
  1099.                           }
  1100.                                                 break;
  1101.  
  1102.         }
  1103.   return(total);
  1104.   }
  1105.  
  1106. /**************************************************************************************************
  1107.  * FUNCTION: HandleDownload()
  1108.  *  PURPOSE: Allows to send specific files to the client (info pages)
  1109.  *    INPUT: *ftp => Master FTP structure
  1110.  *           *arg => Argument (Filename) to retrieve
  1111.  *   RETURN: -
  1112.  **************************************************************************************************/
  1113.  
  1114. static void HandleDownload(struct FTP *ftp, char *arg)
  1115.     {
  1116.   long        datcon=NULL,rc,total;
  1117.     BPTR        fh;
  1118.  
  1119.     if(*fconfig->HowToUploadFile=='\0')
  1120.         {
  1121.     usprintf(ftp->control,CRLF_NOSTRIP,noperm);
  1122.         return;
  1123.         }
  1124.     if(!Stricmp(ftp->cd,"/"))
  1125.         {
  1126.         usprintf(ftp->control,CRLF_NOSTRIP,noperm);
  1127.         return;
  1128.         }
  1129.     if(Stricmp(FilePart(arg),FilePart(fconfig->HowToUploadFile)))
  1130.         {
  1131.     usprintf(ftp->control,CRLF_NOSTRIP,noperm);
  1132.         return;
  1133.         }
  1134.     rc = DataSocket(ftp,fconfig->HowToUploadFile,1);
  1135.   switch(rc)
  1136.         {
  1137.         case    0:    datcon = ftp->pdata;
  1138.                             break;
  1139.         case    1:    datcon = ftp->data;
  1140.                             break;
  1141.         case    -1: return;
  1142.         }
  1143.     if(!(fh = Open(fconfig->HowToUploadFile,MODE_OLDFILE)))
  1144.         {
  1145.         usprintf(ftp->control,CRLF_NOSTRIP,noconn);
  1146.         total = -1;
  1147.         }
  1148.     else
  1149.         {
  1150.         HandleStats("DL: %s",FilePart(arg));
  1151.         total = sendfile(fh,datcon,ftp->type,TRUE);
  1152.         Close(fh);
  1153.         }
  1154.     if(total == -1)
  1155.         {
  1156.         /* An error occurred on the data connection */
  1157.         usprintf(ftp->control,CRLF_NOSTRIP,noconn);
  1158.         shutdown(datcon,2);    /* Blow away data connection */
  1159.         CloseSocket(datcon);
  1160.         return;
  1161.         }
  1162.     else usprintf(ftp->control,CRLF_NOSTRIP,txok,total);
  1163.     shutdown(datcon,1);
  1164.     CloseSocket(datcon);
  1165.     if(!rc) ftp->pdata = -1;
  1166.     else ftp->data = -1;
  1167.     FAMEAdd64(0UL,total,&FameInfo->FileDLBytesHi);
  1168.     FameInfo->FilesDL++;
  1169.     HandleStats("Finished downloading %ld bytes",total);
  1170.     }
  1171.  
  1172. /**************************************************************************************************
  1173.  * FUNCTION: HandleUpload()
  1174.  *  PURPOSE: Retrieves one file from the client and adds the file to conferences playpen dir
  1175.  *    INPUT: *ftp => Master FTP Structure
  1176.  *           *arg => Filename in Question
  1177.  *   RETURN: -
  1178.  **************************************************************************************************/
  1179.  
  1180. static void HandleUpload(struct FTP *ftp, char *arg)
  1181.     {
  1182.   long        datcon=NULL,rc,total,mycnum;
  1183.     BPTR        fh;
  1184.     char        fbuf[384],fname[32];
  1185.  
  1186.     if(CheckIfOnline(ftp->usernumber)==TRUE)
  1187.         {
  1188.     usprintf(ftp->control,CRLF_NOSTRIP,onlinewarn);
  1189.         return;
  1190.         }
  1191.   if(!(ftp->UserFlags & UF_UPLOAD))
  1192.         {
  1193.         usprintf(ftp->control,CRLF_NOSTRIP,noperm);
  1194.         return;
  1195.         }
  1196.     if(!Stricmp(ftp->cd,"/"))
  1197.         {
  1198.         usprintf(ftp->control,CRLF_NOSTRIP,noperm);
  1199.         return;
  1200.         }
  1201.     if(*arg=='\0')    // Upload without Filename is really not possible
  1202.         {
  1203.         usprintf(ftp->control,CRLF_NOSTRIP,unsupp);
  1204.         return;
  1205.     }
  1206.     if(strlen(FilePart(arg))>fconfig->FileNameLength)
  1207.         {
  1208.         usprintf(ftp->control,CRLF_NOSTRIP,fnametoolong,fconfig->FileNameLength);
  1209.         return;
  1210.         }
  1211.     mycnum = GetConfNumber(ftp->cd);
  1212.     if(!mycnum)
  1213.         {
  1214.     DebugLog("ERROR: Got %ld as Confnumber for %s?",mycnum,ftp->cd);
  1215.         usprintf(ftp->control,CRLF_NOSTRIP,fileerror);
  1216.         return;
  1217.         }
  1218.     if(CheckForDoubles(arg,mycnum)==TRUE)                            // Filename already exists, abort upload
  1219.         {
  1220.         usprintf(ftp->control,CRLF_NOSTRIP,fileexists);
  1221.         return;
  1222.         }
  1223.     FAMEStrCopy(fconfig->UploadTempPath,fbuf,255);
  1224.     SPrintf(fname,"UL_CONF%ld_%08lx",mycnum,FindTask(NULL));
  1225.   AddPart(fbuf,fname,383);
  1226.     rc = DataSocket(ftp,arg,0);
  1227.   switch(rc)
  1228.         {
  1229.         case    0:    datcon = ftp->pdata;
  1230.                             break;
  1231.         case    1:    datcon = ftp->data;
  1232.                             break;
  1233.         case    -1: return;
  1234.         }
  1235.     if(!(fh = Open(fbuf,MODE_READWRITE)))
  1236.         {
  1237.     char ioerr[80];
  1238.         Fault(IoErr(),NULL,ioerr,79);
  1239.         DebugLog("UL FAILURE FOR FILE: %s (%s)",fbuf,ioerr);
  1240.     usprintf(ftp->control,CRLF_NOSTRIP,cantmake,arg,ioerr);
  1241.     total = -1;
  1242.         }
  1243.   else
  1244.         {
  1245.         fstats->CurrentConf = mycnum;    // Set actual conferencenr, so that it will be written together with stats
  1246.         HandleStats("UL: %s",FilePart(arg));
  1247.         total = recvfile(fh,datcon,ftp->type);
  1248.         Close(fh);
  1249.         }
  1250.     if(total == -1)                /* An error occurred on the data connection */
  1251.         {
  1252.         shutdown(datcon,2);    /* Blow away data connection */
  1253.         CloseSocket(datcon);
  1254.     DeleteFile(fbuf);
  1255.         usprintf(ftp->control,CRLF_NOSTRIP,noconn);
  1256.         return;
  1257.         }
  1258.     shutdown(datcon,0);
  1259.     CloseSocket(datcon);
  1260.     if(!rc) ftp->pdata = -1;
  1261.     else ftp->data = -1;
  1262.  
  1263.     /*  Add the uploaded file to our ul list so we can add them l8er to the filelist
  1264.      *  Also the file will be moved to the conference playpen directory including
  1265.    *  Description file, so that the user can add the files l8er
  1266.    */
  1267.  
  1268.     if(AddFileToUList(arg,GetFileSize(fbuf),mycnum,ftp,fbuf)==TRUE)
  1269.         {
  1270.         usprintf(ftp->control,CRLF_NOSTRIP,rxok,total);
  1271.         FAMEAdd64(0UL,total,&FameInfo->FileULBytesHi);
  1272.         FameInfo->FilesUL++;
  1273.         fstats->ULFiles++;
  1274.         FAMEAdd64(0UL,total,&fstats->ULBytesHi);
  1275.         HandleStats("Finished Uploading %ld bytes",total);
  1276.         }
  1277.     else
  1278.         {
  1279.         usprintf(ftp->control,CRLF_NOSTRIP,fileerror);
  1280.         }
  1281.     DeleteFile(fbuf);
  1282.     }
  1283.  
  1284. /**************************************************************************************************
  1285.  * FUNCTION: SendTransferStats()
  1286.  *  PURPOSE: Sends actual stats to given socket. Uses struct FameInfo data
  1287.  *    INPUT: Socket where to send the data or -1 to add only to Log
  1288.  *   RETURN: -
  1289.  **************************************************************************************************/
  1290.  
  1291. static void SendTransferStats(long s)
  1292.     {
  1293.     char    ful[40],dul[40];
  1294.     char byestatsstr[]= "221- \r\n221- Transfered bytes: UL: %12s Bytes | DL: %12s Bytes\r\n221- Transfered files: UL: %12ld Files | DL: %12ld Files\r\n";
  1295.  
  1296.     FAMENum64ToStr(FameInfo->FileULBytesHi,FameInfo->FileULBytesLo,FNSF_GROUPING|FNSF_NUMLOCALE,39,ful);
  1297.     FAMENum64ToStr(FameInfo->FileDLBytesHi,FameInfo->FileDLBytesLo,FNSF_GROUPING|FNSF_NUMLOCALE,39,dul);
  1298.   if(s >=0)
  1299.         {
  1300.         usprintf(s,CRLF_NOSTRIP,byestatsstr,ful,dul,FameInfo->FilesUL,FameInfo->FilesDL);
  1301.         }
  1302.     DebugLog("Stats: UL: %s Bytes / %ld Files | DL: %s Bytes / %ld Files",ful,FameInfo->FilesUL,dul,FameInfo->FilesDL);
  1303.     }
  1304.  
  1305. /**************************************************************************************************
  1306.  * FUNCTION: HandleSize()
  1307.  *  PURPOSE: Sends filesize of given file to given socket. (FTP command SIZE <file>)
  1308.  *    INPUT: *ftp => Master FTP Structure
  1309.  *           *arg => Filename in Question
  1310.  *   RETURN: -
  1311.  **************************************************************************************************/
  1312.  
  1313. static void HandleSize(struct FTP *ftp, char *arg)
  1314.     {
  1315.     struct    FTPUploads *f1;
  1316.     long        mycnum;
  1317.  
  1318.     if(!Stricmp(ftp->cd,"/"))
  1319.         {
  1320.         usprintf(ftp->control,CRLF_NOSTRIP,noperm);
  1321.     return;
  1322.         }
  1323.     if(!Stricmp(FilePart(arg),FilePart(fconfig->HowToUploadFile)))
  1324.         {
  1325.         usprintf(ftp->control,CRLF_NOSTRIP,size,GetFileSize(fconfig->HowToUploadFile));
  1326.         return;
  1327.         }
  1328.  
  1329.     // User seems to want the size of some of his own files, so check for the file and
  1330.   // Return size if file can be found, else return file not found error.
  1331.  
  1332.     mycnum = GetConfNumber(ftp->cd);
  1333.     for(f1=(struct FTPUploads *)filelist.mlh_Head;f1!=(struct FTPUploads *)&filelist.mlh_Tail;f1=(struct FTPUploads *)f1->Node.mln_Succ)
  1334.         {
  1335.         if(f1->ConfNum == mycnum && !Stricmp(f1->FileName,FilePart(arg)))
  1336.             {
  1337.             usprintf(ftp->control,CRLF_NOSTRIP,size,f1->FileSize);
  1338.             return;
  1339.             }
  1340.         }
  1341.     usprintf(ftp->control,CRLF_NOSTRIP,filenotfound);
  1342.     }
  1343.  
  1344. /**************************************************************************************************
  1345.  * FUNCTION: HandleFeatures()
  1346.  *  PURPOSE: Returns supported Features of this server according to RFC 2389
  1347.  *    INPUT: *ftp => Master FTP Structure
  1348.  *   RETURN: -
  1349.  **************************************************************************************************/
  1350.  
  1351. static void HandleFeatures(struct FTP *ftp)
  1352.     {
  1353.     usprintf(ftp->control,CRLF_NOSTRIP,"211- Extensions supported:\r\n SIZE\r\n CLNT\r\n211 End\r\n");
  1354.   }
  1355.  
  1356. /**************************************************************************************************
  1357.  * FUNCTION: HandleClient()
  1358.  *  PURPOSE: Takes Client name and version, concatenates them and copy them to fconfig->ClientVersion
  1359.  *    INPUT: *ftp => Master FTP Structure
  1360.  *           *arg => Client Program Info
  1361.  *   RETURN: -
  1362.  **************************************************************************************************/
  1363.  
  1364. static void HandleClient(struct FTP *ftp, char *arg)
  1365.     {
  1366.     if(*arg)
  1367.         {
  1368.         FAMEStrCopy(arg,ftp->ClientVersion,128);
  1369.         }
  1370.     usprintf(ftp->control,CRLF_NOSTRIP,okay);
  1371.     DebugLog("Remote Client is '%s'",ftp->ClientVersion);
  1372.     }
  1373.  
  1374. /**************************************************************************************************
  1375.  * FUNCTION: HandleHelp()
  1376.  *  PURPOSE: Returns either list of all supported commands or try to give help for a specific command
  1377.  *    INPUT: *ftp => Master FTP Structure
  1378.  *           *arg => Command in question
  1379.  *   RETURN: -
  1380.  **************************************************************************************************/
  1381.  
  1382. static void HandleHelp(struct FTP *ftp, char *arg)
  1383.     {
  1384.     char    **lv;
  1385.   char  helpbuf[256],dummy[12];
  1386.     int        cnt = 0;
  1387.  
  1388.     if(*arg)        // User wants help for specific command
  1389.         {
  1390.         for(lv = commands; *lv != NULL; lv++)
  1391.             {
  1392.             if(!Stricmp(arg,*lv))
  1393.                 {
  1394.                 usprintf(ftp->control,CRLF_NOSTRIP,"214 Syntax: %s\r\n",cmdhelp[cnt]);
  1395.                 return;
  1396.         }
  1397.             cnt++;
  1398.             }
  1399.         usprintf(ftp->control,CRLF_NOSTRIP,unimp);
  1400.         return;
  1401.     }
  1402.  
  1403.     // User wants complete list of supported commands
  1404.  
  1405.     usprintf(ftp->control,CRLF_NOSTRIP,"214- The following commands are recognized:\r\n");
  1406.     FAMEStrCopy("   ",helpbuf,255);
  1407.     for(lv = commands; *lv != NULL; lv++)
  1408.         {
  1409.         if(!(cnt % 6) && cnt > 0)
  1410.             {
  1411.             FAMEStrCat("\r\n",helpbuf);
  1412.             usprintf(ftp->control,CRLF_NOSTRIP,helpbuf);
  1413.             FAMEFillMem(helpbuf,0,255);
  1414.             FAMEStrCopy("   ",helpbuf,255);
  1415.             }
  1416.         SPrintf(dummy,"%-9s",FAMEStrToUpper(*lv));
  1417.         FAMEStrCat(dummy,helpbuf);
  1418.         cnt++;
  1419.         }
  1420.     if(*helpbuf)    usprintf(ftp->control,CRLF_NOSTRIP,"%s\r\n",helpbuf);
  1421.     usprintf(ftp->control,CRLF_NOSTRIP,"214 Direct comments to siegel@trsi.org (http://www.saschapfalz.de).\r\n");
  1422.     }
  1423.  
  1424. /**************************************************************************************************
  1425.  * FUNCTION: HandleStat()
  1426.  *  PURPOSE: Handles FTP command STAT
  1427.  *    INPUT: ftp => Master FTP structure
  1428.  *           arg => Optional filename (not supported)
  1429.  *   RETURN: -
  1430.  **************************************************************************************************/
  1431.  
  1432. static  void    HandleStat(struct FTP *ftp, char *arg)
  1433.     {
  1434.     char    ful[40],dul[40];
  1435.  
  1436.     if(*arg)
  1437.         {
  1438.         usprintf(ftp->control,CRLF_NOSTRIP,unimp);
  1439.         return;
  1440.         }
  1441.     FAMENum64ToStr(FameInfo->FileULBytesHi,FameInfo->FileULBytesLo,FNSF_GROUPING|FNSF_NUMLOCALE,39,ful);
  1442.     FAMENum64ToStr(FameInfo->FileDLBytesHi,FameInfo->FileDLBytesLo,FNSF_GROUPING|FNSF_NUMLOCALE,39,dul);
  1443.     usprintf(ftp->control,CRLF_NOSTRIP,"211- Stats:\r\n211- \r\n");
  1444.     usprintf(ftp->control,CRLF_NOSTRIP,"211-   Username: %s\r\n",ftp->username);
  1445.     usprintf(ftp->control,CRLF_NOSTRIP,"211- Conference: %s\r\n",ftp->cd);
  1446.     usprintf(ftp->control,CRLF_NOSTRIP,"211-    Last on: %s (%s)\r\n",fstats->ConnectTime,ftp->IPaddr);
  1447.     usprintf(ftp->control,CRLF_NOSTRIP,"211-    Timeout: %ld seconds\r\n",fconfig->Timeout);
  1448.     usprintf(ftp->control,CRLF_NOSTRIP,"211-   Bytes UL: %s Bytes\r\n",ful);
  1449.     usprintf(ftp->control,CRLF_NOSTRIP,"211-   Bytes DL: %s Bytes\r\n",dul);
  1450.     usprintf(ftp->control,CRLF_NOSTRIP,"211-   Files UL: %ld Files\r\n",FameInfo->FilesUL);
  1451.     usprintf(ftp->control,CRLF_NOSTRIP,"211-   Files DL: %ld Files\r\n",FameInfo->FilesDL);
  1452.     usprintf(ftp->control,CRLF_NOSTRIP,"211 \r\n");
  1453.     }
  1454.  
  1455. /**************************************************************************************************
  1456.  * FUNCTION: CloseLibs()
  1457.  *  PURPOSE: Frees all resources and closes all open libraries.
  1458.  *    INPUT: -
  1459.  *   RETURN: -
  1460.  *     NOTE: Program will be exited when this function is called!
  1461.  **************************************************************************************************/
  1462.  
  1463. void CloseLibs(void)
  1464.     {
  1465.     if(server_socket>=0)
  1466.         {
  1467.         shutdown(server_socket,2);
  1468.         CloseSocket(server_socket);
  1469.         server_socket = -1;
  1470.        }
  1471.     if(confh!=-1 && confh!=NULL)     Close(confh);
  1472.     FreeConferenceList();
  1473.     if(fib)                        FreeDosObject(DOS_FIB,fib); fib = NULL;
  1474.     if(mem_pool)            DeletePool(mem_pool); mem_pool = NULL;
  1475.   if(SocketBase)        CloseLibrary(SocketBase);    SocketBase = NULL;
  1476.     if(UtilityBase)        CloseLibrary(UtilityBase); UtilityBase = NULL;
  1477.   if(LocaleBase)
  1478.         {
  1479.         if(myloc) CloseLocale(myloc);myloc=NULL;
  1480.         CloseLibrary((struct Library *)LocaleBase);    LocaleBase = NULL;
  1481.         };
  1482.     if (FAMEBase)         CloseLibrary((struct Library *)FAMEBase);    FAMEBase = NULL;
  1483.     if(SysLogBase)      CloseLibrary(SysLogBase); SysLogBase = NULL;
  1484.     if(IntuitionBase)    CloseLibrary((struct Library *)IntuitionBase); IntuitionBase = NULL;
  1485.     exit(0);
  1486.     }
  1487.  
  1488. /**************************************************************************************************
  1489.  * FUNCTION: fail()
  1490.  *  PURPOSE: Prints an Error code via EasyRequest and also to the Debug.log file
  1491.  *    INPUT: iocode         => Optional DOS error code if > 0
  1492.  *           errstring  => printf() style format string
  1493.  *                 ...  => Optional arguments for format string
  1494.  *   RETURN: -
  1495.  **************************************************************************************************/
  1496.  
  1497. void fail(long iocode, char *errstring, ...)
  1498.     {
  1499.     char    errbuf[384],ioerr[80];
  1500.  
  1501.     RawDoFmt(errstring, (long *)(&errstring + 1), (void (*))"\x16\xc0\x4e\x75",errbuf);
  1502.     DebugLog("ERROR: %s",errbuf);
  1503.     if(iocode)
  1504.         {
  1505.         Fault(iocode,"\n\nDOS-ERROR",ioerr,79);
  1506.         strcat(errbuf,ioerr);
  1507.         }
  1508.     if(IntuitionBase)
  1509.         {
  1510.         struct EasyStruct MyES=
  1511.             {
  1512.             sizeof(struct EasyStruct),
  1513.             0,
  1514.             NULL,
  1515.       "%s",
  1516.       "Okay",
  1517.             };
  1518.        EasyRequest(NULL,&MyES,NULL,errbuf);
  1519.         }
  1520.     }
  1521.  
  1522. /**************************************************************************************************
  1523.  * FUNCTION: InitStats()
  1524.  *  PURPOSE: Initializes the Stats structure (Things that do not change anymore)
  1525.  *    INPUT: ftp => Master FTP structure
  1526.  *   RETURN: -
  1527.  *    NOTES: Uses global structure fstats
  1528.  **************************************************************************************************/
  1529.  
  1530. static void InitStats(struct FTP *ftp)
  1531.     {
  1532.     SPrintf(fstats->TaskAddress,"%08lx",FindTask(NULL));
  1533.     fstats->UserNumber = ftp->usernumber;
  1534.     FormatStamp(NULL,fstats->ConnectTime,NULL,FALSE);
  1535.   }
  1536.  
  1537. /**************************************************************************************************
  1538.  * FUNCTION: HandleStats()
  1539.  *  PURPOSE: Manages the stats file stored in T:
  1540.  *    INPUT: actionstring    => What the server is currently doing
  1541.  *   RETURN: TRUE = Success, FALSE = Failure
  1542.  **************************************************************************************************/
  1543.  
  1544. static BOOL HandleStats(char *actionstring, ...)
  1545.     {
  1546.     int     cnt = 0,entries,i, found = -1;
  1547.     BPTR        fp;
  1548.  
  1549.     FAMEFillMem(tmpptr,0,sizeof(struct FTPdStats));
  1550.     if(&actionstring+1) RawDoFmt(actionstring,(long *)(&actionstring + 1), (void (*))"\x16\xc0\x4e\x75",fstats->ActionString);
  1551.     else FAMEStrCopy(actionstring,fstats->ActionString,79);
  1552.   while((fp = Lock(lockfile,EXCLUSIVE_LOCK)))        // Respect the lockfile, it is the important thing!
  1553.         {
  1554.         UnLock(fp);
  1555.         Delay(STATS_RETRY_DELAY);
  1556.     }
  1557.     while(cnt < STATS_FILE_RETRY)
  1558.         {
  1559.         if(!(fp = Open(statname,MODE_READWRITE)))        // File is accessed by many instances!
  1560.             {
  1561.             cnt++;
  1562.             Delay(STATS_RETRY_DELAY);
  1563.             continue;
  1564.             }
  1565.         entries = GetFileSizeFH(fp) / sizeof(struct FTPdStats);
  1566.         if(entries)
  1567.             {
  1568.       for(i = 0; i < entries; i++)
  1569.                 {
  1570.                 Seek(fp,i * sizeof(struct FTPdStats),OFFSET_BEGINNING);
  1571.                 if(!Read(fp,tmpptr,sizeof(struct FTPdStats)))
  1572.                     {
  1573.                     DebugLog("Reading stats error: %ld",IoErr());
  1574.           Close(fp);
  1575.                     return(FALSE);
  1576.                     }
  1577.                 if(!Stricmp(tmpptr->TaskAddress,fstats->TaskAddress))
  1578.                     {
  1579.                     found = i;
  1580.                     break;
  1581.                     }
  1582.                 }
  1583.             }
  1584.         if(found!=-1)
  1585.             {
  1586.       Seek(fp, found * sizeof(struct FTPdStats), OFFSET_BEGINNING);
  1587.             }
  1588.         else
  1589.             {
  1590.       Seek(fp,0L,OFFSET_END);
  1591.             }
  1592.     if(Write(fp,fstats,sizeof(struct FTPdStats))!=sizeof(struct FTPdStats))
  1593.             {
  1594.       DebugLog("Writing stats error: %ld",IoErr());
  1595.             }
  1596.         Close(fp);
  1597.         return(TRUE);
  1598.         }
  1599.     DebugLog("Error while trying to open %s: %ld",statname,IoErr());
  1600.     return(FALSE);
  1601.     }
  1602.  
  1603. /**************************************************************************************************
  1604.  * FUNCTION: RemoveFromStats()
  1605.  *  PURPOSE: Removes our own entry from stats list
  1606.  *    INPUT: ftp => Master FTP structure
  1607.  *   RETURN: TRUE = Success, FALSE = Failure
  1608.  **************************************************************************************************/
  1609.  
  1610. static BOOL RemoveFromStats(void)
  1611.     {
  1612.     int   cnt = 0,entries,i,retries;
  1613.     BPTR    fp,fp2,fp3;
  1614.   char  tmpname[32];
  1615.  
  1616.     /*  First we have to make sure that we are alone here, so create lockfile, and wait for it
  1617.    *  to be created until we can proceed. No other instance writes then to stats until lockfile
  1618.    *  is removed again.
  1619.    */
  1620.  
  1621.     retries = 0;
  1622.   while(1)
  1623.         {
  1624.     if(retries > 255) 
  1625.             {
  1626.             fail(NULL,"Cannot remove ourself from the statsfile, inform SieGeL!!!");
  1627.             return(FALSE);
  1628.             }
  1629.         fp3 = Lock(lockfile,SHARED_LOCK);
  1630.         if(fp3)    /* File exists already, someone else is currently writing */
  1631.             {
  1632.             UnLock(fp3);
  1633.             Delay(STATS_RETRY_DELAY);
  1634.             retries++;
  1635.             continue;
  1636.       }
  1637.         if(!(fp3 = Open(lockfile,MODE_NEWFILE)))    /* File cannot be written exclusivly, so another one was faster, wait */
  1638.             {
  1639.             Delay(STATS_RETRY_DELAY);
  1640.             retries++;
  1641.             continue;
  1642.             }
  1643.         Close(fp3);
  1644.         break;
  1645.         }
  1646.     FAMEFillMem(tmpptr,0,sizeof(struct FTPdStats));
  1647.     SPrintf(tmpname,"T:lst.%s",fstats->TaskAddress);
  1648.     while(cnt < STATS_FILE_RETRY)
  1649.         {
  1650.         if(!(fp = Open(statname,MODE_READWRITE)))        // File is accessed by many instances!
  1651.             {
  1652.             cnt++;
  1653.             Delay(STATS_RETRY_DELAY);
  1654.             continue;
  1655.             }
  1656.         entries = GetFileSizeFH(fp) / sizeof(struct FTPdStats);
  1657.         if(entries)
  1658.             {
  1659.             if(!(fp2 = Open(tmpname,MODE_NEWFILE)))
  1660.                 {
  1661.         DebugLog("Cannot create tmp file %s (%ld)?",tmpname,IoErr());
  1662.         Close(fp);
  1663.                 DeleteFile(lockfile);
  1664.                 return(FALSE);
  1665.                 }
  1666.       for(i = 0; i < entries; i++)
  1667.                 {
  1668.                 Seek(fp,i * sizeof(struct FTPdStats),OFFSET_BEGINNING);
  1669.                 if(!Read(fp,tmpptr,sizeof(struct FTPdStats)))
  1670.                     {
  1671.                     DebugLog("Reading stats error: %ld",IoErr());
  1672.           Close(fp);Close(fp2);
  1673.           DeleteFile(tmpname);
  1674.                     DeleteFile(lockfile);
  1675.                     return(FALSE);
  1676.                     }
  1677.                 if(!Stricmp(tmpptr->TaskAddress,fstats->TaskAddress))    // Our record, leave it out and continue
  1678.                     {
  1679.           continue;
  1680.                     }
  1681.                 if(Write(fp2,tmpptr,sizeof(struct FTPdStats))!=sizeof(struct FTPdStats))
  1682.                     {
  1683.                     DebugLog("Cannot write to tmp file %s (%ld) ?",tmpname,IoErr());
  1684.           Close(fp);Close(fp2);
  1685.                     DeleteFile(tmpname);
  1686.                     DeleteFile(lockfile);
  1687.                     return(FALSE);
  1688.                     }
  1689.                 }
  1690.             Close(fp2);
  1691.             }
  1692.     Close(fp);
  1693.     if(FAMEDosMove(tmpname,statname,fconfig->FileBufferSize*1024,NULL)==FALSE) DebugLog("Stats-DosMove() failed: %ld",IoErr());
  1694.         DeleteFile(lockfile);
  1695.         return(TRUE);
  1696.         }
  1697.     DebugLog("Error while trying to open %s: %ld",statname,IoErr());
  1698.     DeleteFile(lockfile);
  1699.     return(FALSE);
  1700.     }
  1701.  
  1702. /**************************************************************************************************
  1703.  * FUNCTION: CountOnlineUser()
  1704.  *  PURPOSE: Counts how many users are currently logged in
  1705.  *    INPUT: -
  1706.  *   RETURN: User Count or -1 in case of an error
  1707.  **************************************************************************************************/
  1708.  
  1709. static long CountOnlineUsers(void)
  1710.     {
  1711.     BPTR    fp;
  1712.     long    cnt = 0,myentries;
  1713.  
  1714.     while(cnt < STATS_FILE_RETRY)
  1715.         {
  1716.         if(!(fp = Open(statname,MODE_OLDFILE)))        // File is accessed by many instances!
  1717.             {
  1718.             if(IoErr()==ERROR_OBJECT_NOT_FOUND)            // IoErr() = 205, this is okay and not treated as error
  1719.                 {
  1720.                 return(0);
  1721.         }
  1722.             cnt++;
  1723.             Delay(STATS_RETRY_DELAY);
  1724.             continue;
  1725.             }
  1726.         ExamineFH(fp,fib);
  1727.         Close(fp);
  1728.         myentries = fib->fib_Size / sizeof(struct FTPdStats);
  1729.         return(myentries);
  1730.     }
  1731.     return(-1);
  1732.     }
  1733.